package com.andryu.opengl.utils

import android.content.res.AssetManager
import android.opengl.GLES30
import com.andryu.base.LogUtils
import java.io.IOException
import java.nio.charset.StandardCharsets

object ShaderUtils {

    private const val TAG = "ShaderUtils"
    /**
     * 加载着色器
     */
    private fun loadShaper(type: Int, shaperCode: String): Int {
        val shaper = GLES30.glCreateShader(type)
        GLES30.glShaderSource(shaper, shaperCode)
        GLES30.glCompileShader(shaper)
        return shaper
    }

    /**
     * 创建program
     * @param assetManager asset管理器
     * @param vertexFileName 片段着色器
     * @param fragmentFileName 顶点着色器
     */
    fun createProgram(assetManager: AssetManager, vertexFileName: String, fragmentFileName: String): Int {
        return createProgram(
            readShaderFromAsset(assetManager,vertexFileName),
            readShaderFromAsset(assetManager ,fragmentFileName)
        )
    }

    /**
     * 根据着色器code生成program
     */
    private fun createProgram(vectorCode:String, fragmentCode:String):Int{
        val vertexShaper = loadShaper(GLES30.GL_VERTEX_SHADER, vectorCode)
        val fragmentShaper = loadShaper(GLES30.GL_FRAGMENT_SHADER, fragmentCode)
        //创建一个空的OpenGLES程序
        var program = GLES30.glCreateProgram()
        //将顶点着色器加入到程序
        GLES30.glAttachShader(program, vertexShaper)
        //将片元着色器加入到程序
        GLES30.glAttachShader(program, fragmentShaper)
        //链接到程序
        GLES30.glLinkProgram(program)

        val compileStatus = IntArray(1)
        GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, compileStatus, 0)
        if (compileStatus[0] == GLES30.GL_FALSE){
            // 获取信息日志长度
            val infoLogLength = IntArray(1)
            GLES30.glGetProgramiv(program, GLES30.GL_INFO_LOG_LENGTH, infoLogLength, 0)

            // 如果有信息日志，则读取并打印它
            if (infoLogLength[0] > 0) {
                val infoLog = GLES30.glGetProgramInfoLog(program)
                LogUtils.d(TAG,"Could not link program: $infoLog")
            }

            // 删除失败的程序对象
            GLES30.glDeleteProgram(program)
            program = 0
        }

        GLES30.glDeleteShader(vertexShaper)
        GLES30.glDeleteShader(fragmentShaper)
        return program
    }

    /**
     * 从assets读取着色器代码
     */
    private fun readShaderFromAsset(assetManager: AssetManager, fileName: String): String {
        return try {
            assetManager.open(fileName).bufferedReader(StandardCharsets.UTF_8).use { reader ->
                reader.readText()
            }
        } catch (e: IOException) {
            throw RuntimeException("Could not read shader file: $fileName", e)
        }
    }

    public fun glCheckError(message:String){
        val status = GLES30.glGetError()
        if (status != GLES30.GL_NO_ERROR){
            LogUtils.d(TAG, "$message  error code $status")
        }
    }
}

